package com.shenjun.bank.handler;

import com.shenjun.bank.config.ExecutorServiceConfig;
import com.shenjun.bank.servers.HelloClient;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class HelloServerHandler extends ChannelInitializer<NioSocketChannel> {

    @Autowired
    private HelloClient helloClient;

    @Override
    protected void initChannel(NioSocketChannel channel) throws Exception {
        log.info("8001服务器连接建立。。。");
        channel.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
        /*
         * long readerIdleTime 表示多久没有读数据了，就会发送心跳检测包检测连接
         * long writerIdleTime 表示多久没有写数据了，就会发送心跳检测包检测连接
         * long allIdleTime 表示多久没有读写数据了，就会发送心跳检测包检测连接
         *
         * IdleStateHandler触发后，就会传递给一下个handler处理，下一个handler的userEventTiggered处理
         * */
        channel.pipeline().addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
        channel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
            @Override
            public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                super.userEventTriggered(ctx, evt);
                if (evt instanceof IdleStateEvent) {
                    IdleStateEvent evt1 = (IdleStateEvent) evt;
                    String eventType = null;
                    switch (evt1.state()) {
                        case READER_IDLE:
                            eventType = "读空闲";
                            break;
                        case WRITER_IDLE:
                            eventType = "写空闲";
                            break;
                        case ALL_IDLE:
                            eventType = "读写空闲";
                            break;
                    }
                    log.info("客户端：[{}],---[{}]---", channel.remoteAddress(), eventType);
                }
            }
        });
        // 添加长度字段解码器
        channel.pipeline().addLast("h1", new LengthFieldBasedFrameDecoder(
                1024, 0, 4,
                0, 4));
        channel.pipeline().addLast("h2", new StringDecoder(CharsetUtil.UTF_8));
        channel.pipeline().addLast("h3", new SimpleChannelInboundHandler<String>() {
            @Override
            public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                log.info("8001服务端收到消息：[{}]", msg);
                ExecutorServiceConfig.getDefaultExecutor().execute(new Runnable() {
                    @Override
                    public void run() {
                        // 这里是业务逻辑处理
                        log.info("子线任务开始执行, 线程编号：【{}】，循环编号：【{}】",
                                Thread.currentThread().getId(), msg);
                        // 为了能看出效果 ，让当前线程阻塞5秒
                        try {
                            Thread.sleep(200);
                            throw new RuntimeException();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        // 处理完业务逻辑，
                        HashMap<String, Object> params = new HashMap<String, Object>();
                        params.put("a1", "处理后数据：" + msg);
                        log.info("完成任务回调, 线程编号：[{}]，回调循环编号：[{}]",
                                Thread.currentThread().getId(), params.get("a1"));
                        helloClient.writeAndFlush(params.get("a1"));
                    }
                });
            }

            // 当客户端连接后，就会触发这个方法
            @Override
            public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
                super.handlerAdded(ctx);
                // id 表示唯一的值
                log.info("handlerAdded被调用，channelId：[{}]", ctx.channel().id().asLongText());
            }

            // 当客户端断开后，就会触发这个方法
            @Override
            public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
                super.handlerRemoved(ctx);
                // id 表示唯一的值
                log.info("handlerRemoved被调用，channelId：[{}]", ctx.channel().id().asLongText());
            }
        });
    }

}
